package gemini.castor.ui.client.page.content.home.apply.personalinfo;

import gemini.basic.exception.IdentityExistedException;
import gemini.basic.model.Address;
import gemini.basic.model.IdentityCard;
import gemini.basic.model.Person;
import gemini.castor.ui.client.ServiceCatalog;
import gemini.castor.ui.client.mvp.callback.AbstractAsyncCallback;
import gemini.castor.ui.client.mvp.single.CastorWidgetDisplay;
import gemini.castor.ui.client.mvp.single.CastorWidgetPresenter;
import gemini.castor.ui.client.page.RootEvent;
import gemini.castor.ui.client.page.content.home.apply.ApplyEvent;
import gemini.castor.ui.client.page.content.home.apply.distributorid.DistributorIDFormObject;
import gemini.castor.ui.client.utils.GuiUtils;
import gemini.castor.ui.client.utils.PlaceConstants;

import java.util.ArrayList;
import java.util.Date;

import ch.elca.gwt.mvp.client.EventBus;
import ch.elca.gwt.mvp.client.place.Place;

import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.HasClickHandlers;
import com.google.inject.Inject;

public class PersonalInfoFormPresenter extends
		CastorWidgetPresenter<PersonalInfoFormPresenter.Display> {

	private Object outputObject;
	
	@Override
	public Object getOutputObject(){
		return outputObject;
	}
	
	@Inject
	public PersonalInfoFormPresenter(Display display, EventBus globalEventBus) {
		super(display, globalEventBus);
	}

	public interface Display extends CastorWidgetDisplay {
		boolean isValidate();
		PersonalInfoFormObject getObject();
		HasClickHandlers getPersionalSubmitClickHandlers();
		String getCaptchaString();
		
		void errorFromServer(String messageCode);
		void loadCaptchaImage();
	}

	public static final Place PLACE = new Place(PlaceConstants.PLACE_REGISTER);

	@Override
	protected void onBind() {

		registerHandler(display.getPersionalSubmitClickHandlers().addClickHandler(
				new ClickHandler() {
					public void onClick(ClickEvent event) {
						if (display.isValidate()) {
							checkCaptcha();
						}
					}
				}));
		
		display.loadData();
	}
	
	private void checkCaptcha() {
		eventBus.fireEvent(new RootEvent(RootEvent.ForwardType.MASK));
		ServiceCatalog.getCheckCaptchaService().performCheck(display.getCaptchaString(),
				new AbstractAsyncCallback<Boolean>() {

					@Override
					public void onSuccess(Boolean result) {
						eventBus.fireEvent(new RootEvent(RootEvent.ForwardType.UN_MASK));
						if (result) {
							if (display.getObject().getPersonalInfoId()
									.isEmpty()) {
								savePersonalInfo();
							} else {
								int pId = Integer.parseInt(display.getObject()
										.getPersonalInfoId());
								checkPersonalInfoId(pId);
							}
						} else {
							display.loadCaptchaImage();
							GuiUtils.alert("CAPTCHA was invalid!");
						}
					}
				});
	}

	private void checkPersonalInfoId(int id){
		// TODO: HNO, call another service with throw exception: person is already has dis acc
		eventBus.fireEvent(new RootEvent(RootEvent.ForwardType.MASK));
		ServiceCatalog.getPersonService().getById(id,
				new AbstractAsyncCallback<Person>() {

					@Override
					public void onSuccess(Person result) {
						eventBus.fireEvent(new RootEvent(RootEvent.ForwardType.UN_MASK));
						if (result != null) {
							if(result.getDistributor() != null){
								display.loadCaptchaImage();
								GuiUtils.alert("This person is already has Distributor account!");
							} else {
								if(result.getPerson() != null){
									forwardIfSuccess(result, result.getPerson(), false);
								} else {
									forwardIfSuccess(result, null, false);
								}
							}
						} else {
							display.loadCaptchaImage();
							GuiUtils.alert("Not found person with this Id!");
						}
					}
				});
	}
	
	private void savePersonalInfo(){
		final PersonalInfoFormObject p = display.getObject();
		
		IdentityCard identityCard = new IdentityCard();
		
		identityCard.setNumber(p.getIdentify().getNumber());
		identityCard.setDateOfExpiry(new Date());
		identityCard.setDateOfIssue(new Date());
		identityCard.setPlaceOfIssue(p.getIdentify().getPlace());
		identityCard.resetId();

		Person person = new Person();
		
		person.setFirstName(p.getPersonalInfo().getFirstName());
		person.setLastName(p.getPersonalInfo().getLastName());
		person.setDateOfBirth(p.getPersonalInfo().getBirthDay());
		person.setEmail(p.getEmail());
		
		person.setSex(p.getPersonalInfo().getSex());
		person.setPhoneNumber(p.getPhone().getPhoneCell());
		
		// TODO: HNO, p.getLanguage() is too long
		person.setLanguageCode(p.getLanguage());
		
		person.setIdentityCard(identityCard);
		
		Address address = new Address();
		address.setAddressLine1(p.getAddress().getLine1());
		address.setAddressLine2(p.getAddress().getLine2());
		address.setCity(p.getAddress().getCity());
		address.setCountry(p.getAddress().getCountry());
		address.setDistrict(p.getAddress().getDistrict());
		address.resetId();
		
		person.setAddress(address);
		
		eventBus.fireEvent(new RootEvent(RootEvent.ForwardType.MASK));
		ServiceCatalog.getPersonService().saveOrUpdate(person,
				new AbstractAsyncCallback<Person>() {

					@Override
					public void onSuccess(Person result) {
						eventBus.fireEvent(new RootEvent(RootEvent.ForwardType.UN_MASK));
						if(p.isWithSpouse()){
							saveSpousePersonalInfo(result);
						} else {
							forwardIfSuccess(result, null, true);
						}
					}
					
					 @Override
					 public void onFailure(final Throwable caught) {
						 if(caught instanceof IdentityExistedException){
							 display.loadCaptchaImage();
							 display.errorFromServer("htmErrorIdentityExisted");
						 } else {
							 super.onFailure(caught);
						 }
					 }
				});
		
	}
	
	// TODO: HNO, create personalInfoInputWidget to get all needed fields
	private void saveSpousePersonalInfo(final Person spouse){
		final PersonalInfoFormObject p = display.getObject();
		
		IdentityCard identityCard = new IdentityCard();
		
		identityCard.setNumber(p.getHoneyIdentify().getNumber());
		identityCard.setDateOfExpiry(new Date());
		identityCard.setDateOfIssue(new Date());
		identityCard.setPlaceOfIssue(p.getHoneyIdentify().getPlace());
		identityCard.resetId();

		Person person = new Person();
		
		person.setFirstName(p.getSpousePersonalInfo().getFirstName());
		person.setLastName(p.getSpousePersonalInfo().getLastName());
		person.setDateOfBirth(p.getSpousePersonalInfo().getBirthDay());
		person.setEmail(p.getEmail());
		
		// TODO: HNO, p.getSex() is too long
		person.setSex(p.getPersonalInfo().getSex());
		person.setPhoneNumber(p.getPhone().getPhoneCell());
		
		// TODO: HNO, p.getLanguage() is too long
		person.setLanguageCode(p.getLanguage());
		
		person.setIdentityCard(identityCard);
		
		person.setAddress(spouse.getAddress());
		
		person.setPerson(spouse);
		
		eventBus.fireEvent(new RootEvent(RootEvent.ForwardType.MASK));
		ServiceCatalog.getPersonService().saveOrUpdate(person,
				new AbstractAsyncCallback<Person>() {

					@Override
					public void onSuccess(Person result) {
						eventBus.fireEvent(new RootEvent(RootEvent.ForwardType.UN_MASK));
						forwardIfSuccess(spouse, result, true);
					}
					
					 @Override
					 public void onFailure(final Throwable caught) {
						 if(caught instanceof IdentityExistedException){
							 display.loadCaptchaImage();
							 display.errorFromServer("htmErrorIdentityExisted");
						 } else {
							 super.onFailure(caught);
						 }
					 }
				});
		
	}
	
	public void forwardIfSuccess(Person mainPerson, Person spouse, boolean showMessage){
		
		if(showMessage){
			String successMsg = "Please remember below information:<br />Your personal Id: "
					+ mainPerson.getId();
			
			if (spouse != null) {
				successMsg += "<br />Your spouse personal Id: " + spouse.getId();
			}
			
			GuiUtils.info(successMsg);
		}
		
		DistributorIDFormObject dObject = new DistributorIDFormObject();
		
		dObject.setPersons(new ArrayList<Person>(2));
		dObject.getPersons().add(mainPerson);
		if (spouse != null) {
			dObject.getPersons().add(spouse);
		}

		outputObject = dObject;
		
		localEventBus.fireEvent(new ApplyEvent(
				ApplyEvent.ForwardType.PERSONAL_SUBMIT));
	}

	@Override
	public Place getPlace() {
		return PLACE;
	}
}
